package com.beiji.lib.pen.device

import android.app.Application
import android.util.Log
import com.beiji.lib.pen.PenLog
import com.beiji.lib.pen.constants.PenConnectState
import com.beiji.lib.pen.model.DotUnit
import com.tqltech.tqlpencomm.*
import com.tqltech.tqlpencomm.bean.Dot
import com.tqltech.tqlpencomm.bean.ElementCode
import com.tqltech.tqlpencomm.bean.PenStatus
import com.tqltech.tqlpencomm.listener.TQLPenSignal
import kotlinx.coroutines.async
import kotlinx.coroutines.delay

/**
 * 数码笔T111
 * Created by X on 2018/7/12.
 */
class PenT111 : IPen(), TQLPenSignal {
    private lateinit var penCommAgent: PenCommAgent
    private var bgWidth: Int = 0
    private var bgHeight: Int = 0

    //当前bookid
    private var mCurrBookId = -1

    companion object {
        const val TAG = "PenT111"

//        const val XDIST_PERUNIT = 1.524f
//        const val YDIST_PERUNIT = 1.524f

        const val BG_REAL_WIDTH = 900
        const val BG_REAL_HEIGHT = 1250

        const val SCALE_RATIO = 1f

        /**
         * A5本子规格
         */
//        const val A5_PAGE_WIDTH = 144.5f
//        const val A5_PAGE_HEIGHT = 210f

        const val A5_PAGE_WIDTH = 148.082f
        const val A5_PAGE_HEIGHT = 211.074f
        const val A5_X_OFFSET = 0f
        const val A5_Y_OFFSET = 0f

        /**
         * A6本子
         */
//        const val A6_PAGE_WIDTH = 180f
//        const val A6_PAGE_HEIGHT = 280.07f//1063  1654

        const val A6_PAGE_WIDTH = 88f
        const val A6_PAGE_HEIGHT = 140f//1063  1654  //142f

        const val A6_X_OFFSET_ODD = 3.8f
        const val A6_X_OFFSET_EVEN = 0.1f
        const val A6_Y_OFFSET = 2.3f


        /**
         * A5横线本规格
         */
        const val A5_PAGE_WIDTH_LINE = 146.08f
        const val A5_PAGE_HEIGHT_LINE = 206.232f
        const val N_A5_X_OFFSET_ODD = 3.6f
        const val N_A5_X_OFFSET_EVEN = 0f
        const val N_A5_Y_OFFSET = 1.8f

        const val A5_100_WIDTH = 182.0333f
        const val A5_100_HEIGHT = 256.0319f

        //techpage
        const val B5_100_WIDTH = 137.16f
//        const val B5_100_HEIGHT = 216.41f
        const val B5_100_HEIGHT = 216.41f

        const val A5_101_WIDTH = 190.245f
        const val A5_101_HEIGHT = 264.965f

        val instance = PenT111()
    }

    override fun init(application: Application) {
        penCommAgent = PenCommAgent.GetInstance(application)
        penCommAgent.setTQLPenSignalListener(this)
        val resources = application.resources
        bgWidth = resources.displayMetrics.widthPixels
        //penCommAgent.setXYDataFormat(1)
    }

    fun getPoint(dotPoint: Float, bgSize: Int, pageSize: Float, dotSpecification: Float): Float {
        var dotPoint = dotPoint
        dotPoint *= bgSize.toFloat()
        val ax = (pageSize / dotSpecification).toFloat()
        dotPoint /= ax
        return dotPoint
    }

    override fun getConnectState(): PenConnectState = currentConnectState

    override fun connect(): Boolean {
        if (penCommAgent.isConnect(penInfo?.macAddress)) {
            return false
        }
        val result = penCommAgent.connect(penInfo?.macAddress)
        currentConnectState = if (result) PenConnectState.CONNECTING else PenConnectState.CONNECT_FAILED
        onConnectStateChanged()
        return result
    }


    override fun disConnect() {
        penCommAgent.disconnect(penInfo?.macAddress)
    }

    override fun onDisconnected() {
        penInfo?.isConnected = false
        currentConnectState = if (currentConnectState == PenConnectState.CONNECTED) PenConnectState.DISCONNECTED else PenConnectState.CONNECT_FAILED
        onConnectStateChanged()
    }

    private var gCurPageID: Int = 0
    private var gCurBookID: Int = 0
    private var prevGPointX = 0F
    private var prevGPointY = 0F

    override fun onReceiveDot(dot: Dot?) {
        Log.i(TAG, "onReceiveDot: " + dot.toString())
        dot ?: return
        //原始dot数据
        penDataListener?.onReceiveTqlDot(dot)
        //转换原始dot数据为DotUnit
        transformDot(dot, false)
    }

    override fun onReceivePenAllStatus(penStatus: PenStatus?) {
        PenLog.i("onReceivePenAllStatus : $penStatus-> $penStatus")
        penStatus ?: return
        penInfo?.apply {
            batteryLevel = penStatus.mPenBattery.toInt()
        }

        penDataListener?.onBatteryLevelChanged(penInfo?.batteryLevel!!)
    }

    override fun onReceivePenBattery(penBattery: Int, p1: Boolean) {
        PenLog.i("onReceivePenBattery : $penBattery-> $penBattery")
        penInfo?.batteryLevel = penBattery.toInt()
        penDataListener?.onBatteryLevelChanged(penInfo?.batteryLevel!!)
    }

    override fun onReceivePenCustomer(p0: String?) {

    }

    override fun onConnected() {
        penInfo?.isConnected = true
        currentConnectState = PenConnectState.CONNECTED
        onConnectStateChanged()
        penCommAgent.setPenEnableLED(false)
        penCommAgent.getPenOfflineDataList()
        async {
            delay(2000)
            penCommAgent.getPenPowerStatus()
//            penCommAgent.getPenAllStatus()
        }
    }

    override fun setPenName(name: String) {}
    override fun requestPenInfo() {
        penCommAgent.getPenPowerStatus()
//        penCommAgent.getPenAllStatus()
    }

    private fun onConnectStateChanged() {
        penDataListener?.onPenConnectStateChanged(currentConnectState)
    }

    @Synchronized
    private fun transformDot(dot: Dot?, isOffline: Boolean = false) {
        Log.i(TAG, "transformDot: " + dot.toString())
        dot ?: return
        Log.i(TAG, "onReceiveDot offline : $isOffline-> $dot")
        val pointZ = dot.force
        if (pointZ < 0 && pointZ != 0) {
            Log.d(TAG, "Pressure=$pointZ  Cut!!!!!")
            return
        }
        if (dot.type == null) {
            Log.e(TAG, "dot.type is null -> $dot")
            //TODO Test code
            dot.type = Dot.DotType.PEN_MOVE
            dot.force = -1
//            return
        }
        //动态计算屏幕高度
        calculatedHeight(dot.BookID)

        Log.i(TAG, dot.toString())

        val tmpX = dot.x.toLong()
        val tmpY = dot.y.toLong()

        var pointX = dot.fx.toFloat()
        pointX /= 100.0f
        pointX += tmpX.toFloat()

        var pointY = dot.fy.toFloat()
        pointY /= 100.0f
        pointY += tmpY.toFloat()

        if (dot.BookID == 3) {

            if (dot.PageID % 2 == 1) {
                pointX -= A6_X_OFFSET_ODD
            } else {
                pointX -= A6_X_OFFSET_EVEN
            }
            pointY -= A6_Y_OFFSET
            pointX *= bgWidth.toFloat()          // BG_WIDTH，控件的宽
            val ax = A6_PAGE_WIDTH / 1.524f
            pointX /= ax
            pointY *= bgHeight.toFloat()         // BG_HEIGHT，控件的高
            val ay = A6_PAGE_HEIGHT / 1.524f
            pointY /= ay

//            pointX = getPoint(dot.ab_x, bgWidth, A6_PAGE_WIDTH, Constants.getXdistPerunit().toFloat())
//            pointY = getPoint(dot.ab_y, bgHeight, A6_PAGE_HEIGHT, Constants.getYdistPerunit().toFloat())

        } else if (dot.BookID == 4) {

            if (dot.PageID % 2 == 1) {
                pointX -= N_A5_X_OFFSET_ODD  //3.6f
            } else {
                pointX -= N_A5_X_OFFSET_EVEN  // 0f
            }
            pointY -= N_A5_Y_OFFSET  //1.8f
            pointX *= BG_REAL_WIDTH.toFloat()          // BG_WIDTH，控件的宽
            val ax = A5_PAGE_WIDTH_LINE / Constants.getXdistPerunit().toFloat()  // 146.08f
            pointX /= ax
            pointY *= BG_REAL_HEIGHT.toFloat()         // BG_HEIGHT，控件的高
            val ay = A5_PAGE_HEIGHT_LINE / Constants.getYdistPerunit().toFloat() // 206.232f
            pointY /= ay

        } else if (dot.BookID == 30) {   //适配BookID 适配本子
            pointX = getPoint(dot.ab_x, bgWidth, A5_100_WIDTH, Constants.getXdistPerunit().toFloat())
            pointY = getPoint(dot.ab_y, bgHeight, A5_100_HEIGHT, Constants.getYdistPerunit().toFloat())

        }  else if (dot.BookID == 100 ) {   //适配BookID 适配本子
            pointX = getPoint(dot.ab_x+1f, bgWidth, B5_100_WIDTH, Constants.getXdistPerunit().toFloat())
            pointY = getPoint(dot.ab_y, bgHeight,B5_100_HEIGHT, Constants.getYdistPerunit().toFloat())

        }else if (dot.BookID == 101) {   //适配BookID 适配本子

            pointX = getPoint(dot.ab_x, bgWidth, A5_101_WIDTH, Constants.getXdistPerunit().toFloat())
            pointY = getPoint(dot.ab_y, bgHeight, A5_101_HEIGHT, Constants.getYdistPerunit().toFloat())

        } else {
            pointX -= A5_X_OFFSET
            pointY -= A5_Y_OFFSET
            pointX *= bgWidth.toFloat()          // BG_WIDTH，控件的宽
            val ax = A5_PAGE_WIDTH / Constants.getXdistPerunit().toFloat()
            pointX /= ax
            pointY *= bgHeight.toFloat()         // BG_HEIGHT，控件的高
            val ay = A5_PAGE_HEIGHT / Constants.getYdistPerunit().toFloat()
            pointY /= ay
            Log.i(TAG, "transformDot: bgWidth=$bgWidth//bgHeight=$bgHeight")
        }


        pointX *= SCALE_RATIO
        pointY *= SCALE_RATIO

        Log.d(TAG, "ImageView width A5_X_OFFSET:" + A5_X_OFFSET + "height:A5_Y_OFFSET " + A5_Y_OFFSET)
        Log.i(TAG, "pointX:" + pointX + "pointY: " + pointY)
        Log.i(TAG, "22pointX:" + pointX.toInt() + "pointY: " + pointY.toInt())
        //处理跨页
        if (dot.type == Dot.DotType.PEN_DOWN) {
            gCurPageID = dot.PageID
            gCurBookID = dot.BookID
        }

        //笔划跨页
        val curPageID = dot.PageID
        var curBookID = dot.BookID
        if (gCurPageID != curPageID || gCurBookID != curBookID) {
            //人工输出PenUp和PenDown
            //上一页
            onReceiveDot(dot.timelong, gCurPageID, gCurBookID, prevGPointX, prevGPointY, dot.force,
                    Dot.DotType.PEN_UP, isOffline)
            //下一页
            onReceiveDot(dot.timelong, curPageID, curBookID, pointX, pointY, dot.force,
                    Dot.DotType.PEN_DOWN, isOffline)
            gCurPageID = curPageID
            gCurBookID = curBookID
        }

        onReceiveDot(dot.timelong, gCurPageID, gCurBookID, pointX, pointY, dot.force, dot.type, isOffline)
        prevGPointX = pointX
        prevGPointY = pointY
    }

    private fun onReceiveDot(time: Long, pageId: Int, bookId: Int, dotX: Float, dotY: Float, force: Int, dotType: Dot.DotType, isOffline: Boolean) {
        val dot = DotUnit().apply {
            this.timestamp = time
            this.pageId = pageId
            this.bookId = bookId
            this.x = dotX
            this.y = dotY
            this.force = force.toFloat()
            this.type = dotType
        }
        if (isOffline) {
            penDataListener?.onOfflineDataReceive(dot)
        } else {
            penDataListener?.onReceiveDot(dot)
        }
    }

    /**
     * 根据屏幕宽度 点码纸宽高 测算出绘制控件高度  适配BookID
     */
    fun calculatedHeight(bookId: Int) {
        if (mCurrBookId != bookId) {
            mCurrBookId = bookId
            bgHeight = when (bookId) {
                3 -> {
                    (bgWidth / A6_PAGE_WIDTH * A6_PAGE_HEIGHT).toInt()
                }
                4 -> {
                    (bgWidth / A5_PAGE_WIDTH_LINE * A5_PAGE_HEIGHT_LINE).toInt()
                }
                30 -> {
                    (bgWidth / A5_100_WIDTH * A5_100_HEIGHT).toInt()
                }
                100 -> {
                    (bgWidth / B5_100_WIDTH * B5_100_HEIGHT).toInt()
                }
                101 -> {
                    (bgWidth / A5_101_WIDTH * A5_101_HEIGHT).toInt()
                }
                else -> {
                    (bgWidth / A5_PAGE_WIDTH * A5_PAGE_HEIGHT).toInt()
                }
            }
        }
    }

    //适配BookID
    fun calculatedHeight(bookId: Int, with: Int): Int {
        Log.i(TAG, "calculatedHeight: with=$with")
        return when (bookId) {
            3 -> {
                (with / A6_PAGE_WIDTH * A6_PAGE_HEIGHT).toInt()
            }
            4 -> {
                (with / A5_PAGE_WIDTH_LINE * A5_PAGE_HEIGHT_LINE).toInt()
            }
            30-> {
                (with / A5_100_WIDTH * A5_100_HEIGHT).toInt()
            }
            100 -> {
                (with / B5_100_WIDTH * B5_100_HEIGHT).toInt()
            }
            101 -> {
                (with / A5_101_WIDTH * A5_101_HEIGHT).toInt()
            }
            else -> {
                (with / A5_PAGE_WIDTH * A5_PAGE_HEIGHT).toInt()
            }
        }
    }

    override fun getPenOfflineDataCount() {
        penCommAgent.getPenOfflineDataList()
    }

    override fun downloadOfflineData() {
        penCommAgent.ReqOfflineDataTransfer(true)
    }

    override fun stopOfflineData() {
        penCommAgent.ReqOfflineDataTransfer(false)
    }

    override fun removeOfflineData() {
        penCommAgent.RemoveOfflineData()
    }

    //该接口不是每次离线数据下载完都会调用,bug
    override fun onFinishedOfflineDownload(p0: Boolean) {
        PenLog.e("onFinishedOfflineDownload -> $p0")
        if (p0) {
            //虽然接口名字是Download，但这个接口是在所有离线笔迹数据都接收完成后回调，所以这里调用的是onOfflineDataReceiveProgress
            penDataListener?.onOfflineDataReceiveProgress(100)
        }
    }

//    override fun onDownloadOfflineProgress(p0: Int) {
//        PenLog.e("onDownloadOfflineProgress -> $p0")
//        penDataListener?.onOfflineDataDownloadProgress(p0)
//    }

    override fun onOfflineDataList(p0: Int) {
        PenLog.e("onOfflineDataList -> $p0")
        penDataListener?.onOfflineDataCount(p0)
    }

    override fun onReceivePenEnableLed(p0: Boolean) {

    }

    override fun onReceiveOfflineStrokes(dot: Dot?) {
        transformDot(dot, true)
    }

    override fun onReceivePenMcuTestCode(p0: String?, p1: Boolean, p2: String?) {

    }

    override fun onReceiveOfflineProgress(p0: Int) {
        PenLog.e("onReceiveOfflineProgress -> $p0")
        penDataListener?.onOfflineDataReceiveProgress(p0)
    }

    override fun onStartOfflineDownload(p0: Boolean) {
        PenLog.e("onStartOfflineDownload -> $p0")
    }

    override fun onPenDeleteOfflineDataResponse(p0: Boolean) {}

    //override fun onPenConfirmRecOfflineDataResponse(p0: Boolean) {}
    //override fun onDownOfflineDataCmdResult(p0: Boolean) {}
    //override fun onOfflineDataListCmdResult(p0: Boolean) {}
    override fun onWriteCmdResult(p0: Int) {}

    override fun onPenChangeLedColorResponse(p0: Boolean) {}
    override fun onPenPauseOfflineDataTransferResponse(p0: Boolean) {
    }


    override fun onReceiveElementCode(p0: ElementCode?, p1: Long) {

    }

    override fun onReceivePenBuzzerBuzzes(p0: Boolean) {

    }

    override fun onReceivePenDotType(p0: Int) {}

    //override fun onReceivePenDotType(p0: Byte) {}
    override fun onReceivePenName(p0: String?) {}

    override fun onPenTimetickSetupResponse(p0: Boolean) {}
    override fun onPenLedConfigResponse(p0: Boolean) {}
    override fun onPenNameSetupResponse(p0: Boolean) {}
    override fun onReceivePenAutoPowerOnModel(p0: Boolean) {}
    override fun onReceivePenTypeInt(p0: Int) {

    }


    override fun onPenContinueOfflineDataTransferResponse(p0: Boolean) {}

    //override fun onUpDown(p0: Boolean) {}
    override fun onReceivePenMac(p0: String?) {}
    override fun onReceiveInvalidReqCode(p0: Boolean) {

    }

    override fun onReceivePenMemory(p0: Int) {}
    override fun onReceivePenType(p0: String) {}
    override fun onException(p0: BLEException?) {
    }

    override fun onPenSensitivitySetUpResponse(p0: Boolean) {}
    override fun onReceiveInvalidSetCode(p0: Boolean) {

    }

    override fun onPenFactoryResetSetUpResponse(p0: Boolean) {}
    override fun onPenAutoPowerOnSetUpResponse(p0: Boolean) {}

    //override fun onReceivePenCustomer(p0: String?) {}
    override fun onReceivePenHandwritingColor(p0: Int) {}

    override fun onReceivePenBtFirmware(p0: String?) {}
    override fun onReceivePresssureValue(p0: Int, p1: Int) {
    }

    override fun onReceivePenTime(p0: Long) {}
    override fun onStopOfflineDownload(p0: Boolean) {
    }

    override fun onReceivePenMcuVersion(p0: String?) {}
    override fun onReceivePenDataType(p0: Byte) {

    }


    //override fun onReceivePenDataType(p0: Int) {}
    override fun onReceivePenSensitivity(p0: Int) {}
    override fun onReceivePenBothCommandData(p0: ByteArray?) {

    }

    override fun onLensOffsetSwitchCallback(p0: Boolean) {

    }

    override fun onPenAutoShutdownSetUpResponse(p0: Boolean) {}
    override fun onPenWriteCustomerIDResponse(p0: Boolean) {

    }

    override fun onReceivePenLedConfig(p0: Int) {}

    //override fun onReceiveOIDFormat(p0: Long) {}
    override fun onPenBeepSetUpResponse(p0: Boolean) {}
    override fun onReceivePenFlashType(p0: Int, p1: Int) {
    }


    override fun onConnectFailed() {
    }

    override fun onReceivePenBeepModel(p0: Boolean) {
    }

    //override fun onReceivePenBeepModel(p0: Boolean?) {}
    override fun onPenDotTypeResponse(p0: Boolean) {}

    //override fun onPenOTAMode(p0: Boolean) {}
    override fun onReceivePenAutoOffTime(p0: Int) {}
    override fun onReceiveInvalidCodeReportingRange(p0: ByteArray?) {

    }
}